package com.lanhai;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import com.lanhai.action.AgvDispatchAction;
import com.lanhai.action.TaskAction;
import com.lanhai.enums.GpType;
import com.lanhai.javaBean.AgvBean;
import com.lanhai.javaBean.GuidepostBean;
import com.lanhai.javaBean.ParkBean;
import com.lanhai.javaBean.StationBean;
import com.lanhai.model.Agv;
import com.lanhai.model.Guidepost;
import com.lanhai.model.Job;
import com.lanhai.model.Park;
import com.lanhai.model.ParkGroup;
import com.lanhai.model.Path;
import com.lanhai.model.PathLock;
import com.lanhai.model.Station;
import com.lanhai.model.TrafficWait;
import com.lanhai.utils.ArrayUtil;
import com.lanhai.utils.HexUtil;
import com.mybatis.dao.AgvDao;
import com.mybatis.dao.ParkDao;
import com.mybatis.dao.StationDao;

import net.sf.json.JSON;

public class MainAction {

	public Main main;
	public AgvDispatchAction agvAction;
	public TaskAction taskAction;
	private static final Logger logger = Logger.getLogger(MainAction.class);

	public void init(Main main) {
		this.main = main;
		initDispatch();
		taskAction = new TaskAction();
		taskAction.init(this);
		main.jobList = new ArrayList<Job>();

	}

	/**
	 * 初始化AGV调度相关
	 */
	private void initDispatch() {
		agvAction = new AgvDispatchAction();
		agvAction.init(MainAction.this);

	}

	public void saveData(JSON json) {

	}

	public void reloadData(Map<String, String> map) {
		String type = map.get("reload");
		if (type.equals("agv")) {
			List<Agv> agvList = AgvBean.loadData(Main.sqlSessionFactory);
			for (Agv agv : agvList) {
				main.agvMap.put(agv.getId(), agv);
			}
		} else if (type.equals("gp")) {
			List<Guidepost> guidepostList = GuidepostBean.loadData(Main.sqlSessionFactory);
			for (Guidepost gd : guidepostList) {
				Guidepost sgd = main.guidepostMap.get(gd.getNum());
				sgd.setType(gd.getType());
				sgd.setStep(gd.getStep());
				sgd.setMapX(gd.getMapX());
				sgd.setMapY(gd.getMapY());
				main.guidepostMap.put(sgd.getNum(), sgd);
			}
		} else if (type.equals("park")) {
			List<Park> parkList = ParkBean.loadData(Main.sqlSessionFactory);
			for (Park park : parkList) {
				Park spark = main.parkMap.get(park.getId());
				spark.setDot(park.getDot());
				spark.setType(park.getType());
				spark.setSname(park.getSname());
				spark.setName(park.getName());
				spark.setStationName(park.getStationName());
				spark.setStep(park.getStep());
				spark.setOutNum(park.getOutNum());
				main.parkMap.put(park.getId(), park);
			}
		} else if (type.equals("station")) {
			List<Station> stationList = StationBean.loadData(Main.sqlSessionFactory);
			for (Station ss : stationList) {
				Station station = main.stationMap.get(ss.getName());
				station.setPGroup(ss.getPGroup());
				station.setPType(ss.getPType());
				station.setState(ss.getState());
				station.setIsClear(ss.getIsClear());
				main.stationMap.put(station.getName(), station);
			}
		}
	}

	/**
	 * 根据名称获取站点
	 * 
	 * @param name
	 * @return
	 */
	public Station getStationByName(String name) {
		Station station = null;
		for (Map.Entry<String, Station> m : main.stationMap.entrySet()) {
			Station sa = m.getValue();
			if (sa.getName().equals(name)) {
				station = sa;
				break;
			}
		}
		return station;
	}

	public Station getStationByIp(String ip, int port) {
		Station station = null;
		for (Map.Entry<String, Station> m : main.stationMap.entrySet()) {
			Station sa = m.getValue();
			if (sa.getIpAddress().equals(ip) && (sa.getPort() == port || sa.getPort() == 0)) {
				station = sa;
				break;
			}
		}
		return station;
	}

	public Station getStationByAgentId(int id) {
		Station station = null;
		for (Map.Entry<String, Station> m : main.stationMap.entrySet()) {
			Station sa = m.getValue();
			if (sa.getAgentLocalId() == id && id != 0) {
				station = sa;
				break;
			}
		}
		return station;
	}

	public List<Station> getStationListByIp(String ip, int port) {
		List<Station> staList = new ArrayList<Station>();
		for (Map.Entry<String, Station> m : main.stationMap.entrySet()) {
			Station sa = m.getValue();
			if (sa.getIpAddress().equals(ip) && (sa.getPort() == port || sa.getPort() == 0)) {
				staList.add(sa);
			}
		}
		return staList;
	}

	public List<Station> getStationListByAgentId(int id) {
		List<Station> staList = new ArrayList<Station>();
		for (Map.Entry<String, Station> m : main.stationMap.entrySet()) {
			Station sa = m.getValue();
			if (sa.getAgentLocalId() == id && id != 0) {
				staList.add(sa);
			}
		}
		return staList;
	}

	/**
	 * 以待命位置编号对AGV列表进行排序
	 * 
	 * @param agvList
	 * @return
	 */
	public List<Agv> NumberSort(List<Agv> agvList) {
		Collections.sort(agvList, new Comparator<Object>() {
			public int compare(Object a, Object b) {
				int one = ((Agv) a).getNumber();
				int two = ((Agv) b).getNumber();
				return two - one;// 降序
			}
		});
		return agvList;
	}

	/**
	 * 根据地标获取泊位
	 * 
	 * @param dot
	 * @return
	 */
	public Park getParkByDot(int dot) {
		Park park = null;
		Map<Integer, Park> parkMap = main.parkMap;
		for (Map.Entry<Integer, Park> m : parkMap.entrySet()) {
			Park p = m.getValue();
			if (p.getDot() == dot) {
				park = p;
				break;
			}
		}
		return park;
	}
	
	/**
	 * 根据名称获取泊位
	 * 
	 * @param dot
	 * @return
	 */
	public Park getParkByName(String name) {
		Park park = null;
		Map<Integer, Park> parkMap = main.parkMap;
		for (Map.Entry<Integer, Park> m : parkMap.entrySet()) {
			Park p = m.getValue();
			if (p.getName().equals(name)) {
				park = p;
				break;
			}
		}
		return park;
	}

	/**
	 * 根据离开点地标号获取泊位
	 * 
	 * @param dot
	 * @return
	 */
	public Park getParkByOutNum(int num) {
		Park park = null;
		Map<Integer, Park> parkMap = main.parkMap;
		for (Map.Entry<Integer, Park> m : parkMap.entrySet()) {
			Park p = m.getValue();
			if (p.getOutNum() == num) {
				park = p;
				break;
			}
		}
		return park;
	}

	/**
	 * 根据【线别】名称获取泊位
	 * 
	 * @param name
	 * @return
	 */
	public Park getParkByStationName(String name) {
		Park park = null;
		Map<Integer, Park> parkMap = main.parkMap;
		for (Map.Entry<Integer, Park> m : parkMap.entrySet()) {
			Park p = m.getValue();
			if (p.getStationName().equals(name)) {
				park = p;
				break;
			}
		}
		return park;
	}

	/**
	 * 根据地标号获取地标对像
	 * 
	 * @param num
	 * @return
	 */
	public Guidepost getGuidepostByNum(int num) {
		Guidepost gp = null;
		for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
			Guidepost g = m.getValue();
			if (g.getNum() == num) {
				gp = g;
				break;
			}
		}
		return gp;
	}

	/**
	 * 根据工序获取选择点
	 * 
	 * @param num
	 * @return
	 */
	public Guidepost getGuidepostByXZDNum(int step) {
		Guidepost gp = null;
		for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
			Guidepost g = m.getValue();
			if (g.getStep() == step && g.getType() == 12) {
				gp = g;
				break;
			}
		}
		return gp;
	}
	
	/**
	 * 根据工序，区域获取选择点,
	 * 
	 * @param num
	 * @return
	 */
	public Guidepost getGuidepostByXZDNum(int step,int area) {
		Guidepost gp = null;
		for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
			Guidepost g = m.getValue();
			if (g.getStep() == step && g.getType() == 12 && g.getXzdNumItem() == area) {
				gp = g;
				break;
			}
		}
		return gp;
	}

	/**
	 * 根据地标获取站点分组
	 * 
	 * @param dot
	 * @return
	 */
	public ParkGroup getParkGroupByInDot(int dot) {
		ParkGroup parkGroup = null;
		for (Map.Entry<Integer, ParkGroup> m : main.parkGroupMap.entrySet()) {
			ParkGroup pg = m.getValue();
			if (pg.getInDot() == dot) {
				parkGroup = pg;
				break;
			}
		}
		return parkGroup;
	}

	/**
	 * 根据key值获取线路
	 * 
	 * @param key
	 * @return
	 */
	public Path getPathByKey(String key) {
		Path path = null;
		for (Path p : main.pathList) {
			if (p.getKey().equals(key)) {
				path = p;
			}
		}
		return path;
	}

	/**
	 * 根据Step获取地标type为选择点的列表
	 * 
	 * @param key
	 * @return
	 */
	public Guidepost getGuidepostByStep(int step) {
		Guidepost gp = null;
		for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
			if (m.getValue().getType() == GpType.XZD.getCode() && m.getValue().getStep() == step) {
				gp = m.getValue();
			}
		}
		return gp;
	}

	/**
	 * 根据Step获取地标type为选择点，机台为一列的
	 * 
	 * @param key
	 * @return
	 */
	public Guidepost getGuidepostByStep4Station(int step, int step2,Agv agv) {
		Guidepost gp = null;
		Station station = null;
		if (step2 != 0) {
			station = agvAction.getFreeStationByStep2(step2,agv);
		} else {
			station = agvAction.getFreeStationByStep2(step,agv);
		}
		if (station != null && agvAction.checkAgvGoal(getParkByStationName(station.getName()))) {
			for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
				if (m.getValue().getType() == GpType.XZD.getCode() && m.getValue().getStep() == step
						&& m.getValue().getXzdNumItem() == station.getLimit()) {
					gp = m.getValue();
				}
			}
		}

		return gp;
	}

	/**
	 * 根据Step获取地标type为选择点的列表，分区域式选择点
	 * 
	 * @param key
	 * @return
	 */
	public Guidepost getGuidepostByStep2(int step, int xzdNumItem) {
		Guidepost gp = null;
		for (Map.Entry<Integer, Guidepost> m : main.guidepostMap.entrySet()) {
			if (m.getValue().getType() == GpType.XZD.getCode() && m.getValue().getStep() == step
					&& m.getValue().getXzdNumItem() == xzdNumItem) {
				gp = m.getValue();
			}
		}
		return gp;
	}

	/**
	 * 根据起点和终点来获取线路
	 * 
	 * @param num
	 * @param dot
	 * @return
	 */
	public Path getPathByNumOrDot(String num, String dot) {
		Path path = null;
		for (Path p : main.pathList) {
			if (p.getItemNote() != null && p.getItemNote().length > 0) {
				for (String st : p.getItemNote()) {
					if (st.equals(num) && p.getItemNote()[p.getItemNote().length - 1].equals(dot)) {
						path = p;
						break;
					}
				}
			}

		}
		return path;
	}

	/**
	 * 根据线路号获取线路锁对象
	 * 
	 * @param item
	 * @return
	 */
	public PathLock getpathLockByItem(int item) {
		PathLock pathLock = null;
		for (Map.Entry<Integer, PathLock> m : main.pathLockMap.entrySet()) {
			PathLock pl = m.getValue();
			if (pl.getItem() == item) {
				pathLock = pl;
				break;
			}
		}
		return pathLock;
	}

	/**
	 * 更新机台的信息到数据库的临时表
	 * 
	 * @param station
	 * @throws Exception
	 */
	public void updateTempStation(String stationName) {
		main.pool.execute(new Runnable() {
			@Override
			public void run() {
				Station station = getStationByName(stationName);
				SqlSession sqlSession = Main.sqlSessionFactory.openSession();
				try {
					StationDao dao = sqlSession.getMapper(StationDao.class);
					dao.updateTempData(station);
					sqlSession.commit();
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					sqlSession.close();
				}
			}
		});
	}

	/**
	 * 将station更新到数据库
	 * 
	 * @param stationName
	 */
	public void updateStation(String stationName) {
		main.pool.execute(new Runnable() {
			@Override
			public void run() {
				Station station = getStationByName(stationName);
				SqlSession sqlSession = Main.sqlSessionFactory.openSession();
				try {
					StationDao dao = sqlSession.getMapper(StationDao.class);
					dao.update(station);
					sqlSession.commit();
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					sqlSession.close();
				}
			}
		});
	}

	/**
	 * 更新机台的信息到数据库的临时表
	 * 
	 * @param station
	 * @throws Exception
	 */
	public void updateTempPark(int id) {
		main.pool.execute(new Runnable() {
			@Override
			public void run() {
				Park park = main.parkMap.get(id);
				SqlSession sqlSession = Main.sqlSessionFactory.openSession();
				try {
					ParkDao dao = sqlSession.getMapper(ParkDao.class);
					dao.updateTempData(park);
					sqlSession.commit();
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					sqlSession.close();
				}
			}
		});
	}

	/**
	 * 将最新的AGV数据同步到数据库中的临时表
	 * 
	 * @param agv
	 */
	public void updateTempAgv(Agv agv) {
		main.pool.execute(new Runnable() {
			@Override
			public void run() {
				SqlSession sqlSession = Main.sqlSessionFactory.openSession();
				try {
					AgvDao agvDao = sqlSession.getMapper(AgvDao.class);
					agvDao.updateTempData(agv);
					sqlSession.commit();
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					sqlSession.close();
				}
			}
		});
	}

	/**
	 * 将最新的AGV数据同步到数据库中的临时表
	 * 
	 * @param agv
	 */
	public void insertTempAgv(Agv agv) {
		main.pool.execute(new Runnable() {
			@Override
			public void run() {
				SqlSession sqlSession = Main.sqlSessionFactory.openSession();
				try {
					AgvDao agvDao = sqlSession.getMapper(AgvDao.class);
					agvDao.insertTempData(agv);
					sqlSession.commit();
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					sqlSession.close();
				}
			}
		});
	}

	/**
	 * 获取当前工序、线别AGV的数量
	 * 
	 * @param step
	 * @return
	 */
	public Integer stepAgvQty(int step, int pGroup) {
		int qty = 0;
		for (Map.Entry<Integer, Agv> m : main.agvMap.entrySet()) {
			if (m.getValue().getStep() == step && m.getValue().getpGroup() == pGroup) {
				qty = qty + 1;
			}
		}
		return qty;
	}

	/**
	 * fins回调方法 isRead:1、读PLC写入地址，2、调度写入，3、读调度写入地址
	 */
	public void finsResponse(byte[] buf, String ip, int isRead, int port) {
		if (buf[12] == 0 && buf[13] == 0) {
			if (buf[11] == 1) {// 等于“1”，读操作
				byte[] rdata = new byte[8];
				rdata[0] = buf[14];
				rdata[1] = buf[15];
				rdata[2] = buf[16];
				rdata[3] = buf[17];
				rdata[4] = buf[18];
				rdata[5] = buf[19];
				rdata[6] = buf[20];
				rdata[7] = buf[21];
				String type = "";
				if (isRead == 1 && rdata[1] > 0) {// 读到PLC写入的数据执行
					type = "PLC地址";
					logger.info("PLC写入的数据：" + HexUtil.byte2HexStr(rdata));
					taskAction.handle(rdata, ip, port);
				} else if (isRead == 3) {
					type = "调度地址";
					updateCache(rdata, ip, port);// 检查PLC的寄存器，确保完成对接后被清空
				}
//				else{
//					checkCheck(rdata, ip);//检查PLC的寄存器，确保完成对接后被清空
//					logger.info("调度写入的数据：" + HexUtil.byte2HexStr(rdata));
//				}
				logger.info("接收数据111111," + type + "：" + HexUtil.byte2HexStr(rdata));
			} else {// 等于“2”，写操作
				logger.info("写入PCL寄存器成功，IP：" + ip);
			}
		} else {
			logger.error("PCL返回错误码!");
		}
		// logger.info("receive:" + HexUtil.byte2HexStr(buf));
	}

	/**
	 * 将读取回来的PCL内存值更新到model
	 * 
	 * @param buf
	 * @param ipAddress
	 */
	public void updateCache(byte[] buf, String ipAddress, int port) {
		Station station = getStationByIp(ipAddress, port);
		if (station != null) {
			String cacheStr = HexUtil.byte2HexStr(buf);
			station.setCacheStr(cacheStr);
			main.stationMap.put(station.getName(), station);
		}
	}

	
	/**
	 * 用机台的最后对接时间进行排序
	 * 
	 * @param stationList
	 * @return
	 */
	public List<Station> lastJoinTimeSort(List<Station> stationList) {
		Collections.sort(stationList, new Comparator<Object>() {
			public int compare(Object a, Object b) {
				long one = ((Station) a).getLastJoinTime().getTime();
				long two = ((Station) b).getLastJoinTime().getTime();
				int x = 0;
				if (one > two) {
					x = 1;
				} else if (one < two) {
					x = -1;
				}
				return x;
			}
		});
		return stationList;
	}
	
	/**
	 * 用机台的出料多少进行排序
	 * 
	 * @param stationList
	 * @return
	 */
	public List<Station> lastOuttiSort(List<Station> stationList) {
		Collections.sort(stationList, new Comparator<Object>() {
			public int compare(Object a, Object b) {
				long one = ((Station) a).getOutQuantity();
				long two = ((Station) b).getOutQuantity();
				int x = 0;
				if (one < two) {
					x = 1;
				} else if (one > two) {
					x = -1;
				} 
				return x;
			}
		});
		return stationList;
	}
	
	/**
	 * 用机台的进料多少进行排序
	 * 
	 * @param stationList
	 * @return
	 */
	public List<Station> lastIntiSort(List<Station> stationList) {
		Collections.sort(stationList, new Comparator<Object>() {
			public int compare(Object a, Object b) {
				long one = ((Station) a).getInQuantity();
				long two = ((Station) b).getInQuantity();
				int x = 0;
				if (one > two) {
					x = 1;
				} else if (one < two) {
					x = -1;
				} 
				return x;
			}
		});
		return stationList;
	}

	/**
	 * 
	 * @param twList
	 * @return
	 */
	public List<TrafficWait> trafficWaitSort(List<TrafficWait> twList) {
		Collections.sort(twList, new Comparator<Object>() {
			public int compare(Object a, Object b) {
				double one = ((TrafficWait) a).getDistance();
				double two = ((TrafficWait) b).getDistance();
				int x = 0;
				if (one > two) {
					x = 1;
				} else if (one < two) {
					x = -1;
				}
				return x;
			}
		});
		return twList;
	}

	public Agv getAgvByIp(String ip) {
		Agv agv = null;
		for (Map.Entry<Integer, Agv> m : main.agvMap.entrySet()) {
			if (m.getValue().getIpAddress().equals(ip)) {
				agv = m.getValue();
			}
		}

		return agv;
	}

	/**
	 * 根据终点获取路径列表
	 *
	 * @param gp
	 * @param goal
	 */
	public List<Path> getPathListByGoal(Guidepost gp, int goal) {
		List<Path> paths = new ArrayList<>();
		boolean flag = true;
		int oneNum = -1;
		int go = -1;
		while (oneNum != gp.getNum() && flag) {
			for (Map.Entry<String, Path> p : main.mapPathMap.entrySet()) {
				Path path = p.getValue();
				String[] itemNote = path.getItemNote();
				if (itemNote != null) {
					int dest = Integer.parseInt(itemNote[itemNote.length - 1]);// 获取最后的点位
					if (goal == dest && go == -1) {
						paths.add(path);
						oneNum = Integer.parseInt(itemNote[0]);
						go = oneNum;
						break;
					} else if (go != -1) {
						if (go == dest) {
							paths.add(path);
							oneNum = Integer.parseInt(itemNote[0]);
							go = oneNum;
							break;
						}
					} else if (ArrayUtil.contains(itemNote, oneNum)) {
						paths.add(path);
					}
				}

			}
			if (oneNum == gp.getNum()) {
				flag = false;
			}

		}
		// 倒序 先加后排
		Collections.reverse(paths);

		for (Path path : paths) {
			System.out.println(path);
		}
		return paths;
	}

//	public void checkCache(byte[] buf, String ipAddress){
//		Station station = getStationByIp(ipAddress);
//		if(buf[1] > 0 && station.getIsClear() == 1){//第一个字节大于0，并且记录标记为“需要清空”
//			String plcIp = station.getIpAddress();
//			int plcPort = station.getPort();
//			String pcIp = main.localIp;
//			int option = 2;//写入
//			int target = station.getWriteTar();
//			byte[] ndata = {(byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0};
//			byte[] sendByte = CommandUtil.getFinsWriteData(plcIp, plcPort, pcIp, option, target, ndata);
//    		byte[] result = UDPUtil.sendData4Fins(sendByte, plcIp, plcPort, Main.parkSendPort, option, this, 2);
//    		logger.info(HexUtil.byte2HexStr(result));		
//		}
//	}

}